﻿using System;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Input;
using Gmantis.Controls.Extended;

namespace Gmantis.Controls.DataGrid
{
    public enum DataGridDateTimeColumnEditMode
    {
        Date,
        Time,
        DateTime,
        Custom
    }

    public class DataGridDateTimeColumn : DataGridBoundColumn
    {
        // Fields
        private bool _customFormatSet;
        private DataGridDateTimeColumnEditMode _editMode;
        private DayOfWeek _firstDayOfWeek;
        private bool _firstDayOfWeekSet;
        private string _format;
        public static readonly DependencyProperty DateFormatProperty = DependencyProperty.Register("DateFormat", typeof(Gmantis.Controls.Extended.DatePickerFormat), typeof(DataGridDateTimeColumn), new PropertyMetadata(Gmantis.Controls.Extended.DatePickerFormat.Short));
        public static readonly DependencyProperty MaxDateProperty = DependencyProperty.Register("MaxDate", typeof(DateTime), typeof(DataGridDateTimeColumn), new PropertyMetadata(DateTime.MaxValue));
        public static readonly DependencyProperty MinDateProperty = DependencyProperty.Register("MinDate", typeof(DateTime), typeof(DataGridDateTimeColumn), new PropertyMetadata(DateTime.MinValue));
        public static readonly DependencyProperty TimeFormatProperty = DependencyProperty.Register("TimeFormat", typeof(TimeEditorFormat), typeof(DataGridDateTimeColumn), new PropertyMetadata(TimeEditorFormat.ShortTime));

        // Methods
        public DataGridDateTimeColumn()
        {
            this.Initialize();
        }

        public DataGridDateTimeColumn(PropertyInfo property)
            : base(property)
        {
            this.Initialize();
        }

        public override bool BeginEdit(FrameworkElement editingElement, RoutedEventArgs routedEventArgs)
        {
            if ((editingElement is TextBoxBase) && (routedEventArgs is System.Windows.Input.KeyEventArgs))
            {
                string keyString = KeyboardUtil.GetKeyString((System.Windows.Input.KeyEventArgs)routedEventArgs);
                (editingElement as TextBoxBase).Text = keyString;
            }
            return true;
        }

        public override void CancelCellEdit(FrameworkElement editingElement, object uneditedValue)
        {
            if (editingElement is DateTimePicker)
            {
                (editingElement as DateTimePicker).DateTime = (DateTime?)uneditedValue;
            }
            if (editingElement is TextBoxBase)
            {
                (editingElement as TextBoxBase).Text = (string)uneditedValue;
            }
        }

        public override void EndEdit(FrameworkElement editingElement)
        {
            DateTimePicker picker = editingElement as DateTimePicker;
            if (picker != null)
            {
                picker.FinalizeEditing();
                BindingExpression bindingExpression = picker.GetBindingExpression(DateTimePicker.DateTimeProperty);
                if (bindingExpression != null)
                {
                    bindingExpression.UpdateSource();
                }
            }
            TextBoxBase base2 = editingElement as TextBoxBase;
            if (base2 != null)
            {
                BindingExpression expression2 = base2.GetBindingExpression(TextBoxBase.GTextProperty);
                if (expression2 != null)
                {
                    expression2.UpdateSource();
                }
            }
        }

        public override FrameworkElement GetCellEditingContent(DataGridRow row)
        {
            System.Windows.Controls.Control control;
            if (this.EditMode == DataGridDateTimeColumnEditMode.Custom)
            {
                control = new TextBoxBase();
                if (base.Binding != null)
                {
                    Binding binding = base.CopyBinding(base.Binding, null);
                    control.SetBinding(System.Windows.Controls.TextBox.TextProperty, binding);
                }
            }
            else
            {
                DateTimePicker picker = new DateTimePicker();
                switch (this.EditMode)
                {
                    case DataGridDateTimeColumnEditMode.Date:
                        picker.EditMode = DateTimePickerEditMode.Date;
                        break;

                    case DataGridDateTimeColumnEditMode.Time:
                        picker.EditMode = DateTimePickerEditMode.Time;
                        break;
                }
                picker.DateFormat = this.DateFormat;
                picker.TimeFormat = this.TimeFormat;
                picker.HorizontalAlignment = base.HorizontalAlignment;
                picker.AllowNull = base.AllowNull;
                picker.MaxDate = this.MaxDate;
                picker.MinDate = this.MinDate;
                if (this._firstDayOfWeekSet)
                {
                    picker.FirstDayOfWeek = this.FirstDayOfWeek;
                }
                picker.Padding = new Thickness(0.0);
                picker.CornerRadius = new CornerRadius(0.0);
                if (base.Binding != null)
                {
                    Binding binding2 = base.CopyBinding(base.Binding, null);
                    picker.SetBinding(DateTimePicker.DateTimeProperty, binding2);
                }
                picker.AddHandler(UIElement.KeyDownEvent, new KeyEventHandler(this.picker_KeyDown), true);
                control = picker;
            }
            control.VerticalContentAlignment = base.VerticalAlignment;
            if (base.CellEditingContentStyle != null)
            {
                control.Style = base.CellEditingContentStyle;
            }
            return control;
        }

        public override IDataGridFilter GetFilter()
        {
            DataGridFilter filter = new DataGridFilter();
            DataGridDateTimeFilter target = new DataGridDateTimeFilter
            {
                DateFormat = this.DateFormat,
                TimeFormat = this.TimeFormat
            };
            if (this._firstDayOfWeekSet)
            {
                target.FirstDayOfWeek = this.FirstDayOfWeek;
            }
            target.SetBinding<DataGrid>(Control.BackgroundProperty, base.DataGrid, dg => dg.HeaderBackground);
            target.SetBinding<DataGrid>(Control.ForegroundProperty, base.DataGrid, dg => dg.HeaderForeground);
            target.SetBinding<DataGrid>(Control.BorderBrushProperty, base.DataGrid, dg => dg.BorderBrush);
            target.SetBinding<DataGrid>(DataGridDateTimeFilter.MouseOverBrushProperty, base.DataGrid, dg => dg.MouseOverBrush);
            target.SetBinding<DataGrid>(DataGridDateTimeFilter.PressedBrushProperty, base.DataGrid, dg => dg.PressedBrush);
            target.SetBinding<DataGrid>(DataGridDateTimeFilter.SelectedBackgroundProperty, base.DataGrid, dg => dg.SelectedBackground);
            target.SetBinding<DataGrid>(DataGridDateTimeFilter.FocusBrushProperty, base.DataGrid, dg => dg.SelectedBackground);
            target.SetBinding<DataGrid>(DataGridDateTimeFilter.InputBackgroundProperty, base.DataGrid, dg => dg.RowBackground);
            target.SetBinding<DataGrid>(DataGridDateTimeFilter.InputForegroundProperty, base.DataGrid, dg => dg.RowForeground);
            if (((base.Binding != null) && (this.ActualFilterMemberPath != base.Binding.Path.Path)) && (this.EditMode == DataGridDateTimeColumnEditMode.Time))
            {
                target.EditMode = DateTimePickerEditMode.Time;
            }
            else
            {
                target.EditMode = (this.EditMode == DataGridDateTimeColumnEditMode.Date) ? DateTimePickerEditMode.Date : DateTimePickerEditMode.DateTime;
            }
            filter.InnerControl = target;
            return filter;
        }

        private void Initialize()
        {
            base.HorizontalAlignment = HorizontalAlignment.Right;
            this._editMode = DataGridDateTimeColumnEditMode.DateTime;
            this._format = "g";
        }

        private void picker_KeyDown(object sender, System.Windows.Input.KeyEventArgs e)
        {
            if ((e.Key == Key.Enter) && ((e.OriginalSource is DatePickerTextBox) || (e.OriginalSource is MaskedTextBox)))
            {
                e.Handled = false;
            }
        }

        public override object PrepareCellForEdit(FrameworkElement editingElement)
        {
            if (editingElement is DateTimePicker)
            {
                return (editingElement as DateTimePicker).DateTime;
            }
            if (editingElement is TextBoxBase)
            {
                return (editingElement as TextBoxBase).Text;
            }
            return null;
        }

        // Properties
        public Gmantis.Controls.Extended.DatePickerFormat DateFormat
        {
            get
            {
                return (Gmantis.Controls.Extended.DatePickerFormat)base.GetValue(DateFormatProperty);
            }
            set
            {
                base.SetValue(DateFormatProperty, value);
            }
        }

        public override IValueConverter DefaultConverter
        {
            get
            {
                return new DataGridDateTimeConverter();
            }
        }

        public DataGridDateTimeColumnEditMode EditMode
        {
            get
            {
                return this._editMode;
            }
            set
            {
                this._editMode = value;
                if (!this._customFormatSet)
                {
                    switch (this._editMode)
                    {
                        case DataGridDateTimeColumnEditMode.Date:
                            this._format = "d";
                            break;

                        case DataGridDateTimeColumnEditMode.Time:
                            this._format = "t";
                            break;

                        case DataGridDateTimeColumnEditMode.DateTime:
                            this._format = "g";
                            break;
                    }
                }
                if (base.DataGrid != null)
                {
                    base.DataGrid.Refresh(false, true, true, true, true);
                }
            }
        }

        public DayOfWeek FirstDayOfWeek
        {
            get
            {
                return this._firstDayOfWeek;
            }
            set
            {
                this._firstDayOfWeek = value;
                this._firstDayOfWeekSet = true;
                if (base.DataGrid != null)
                {
                    base.DataGrid.Refresh(false, true, true, true, true);
                }
            }
        }

        public override string Format
        {
            get
            {
                return this._format;
            }
            set
            {
                this._format = value;
                this._customFormatSet = true;
                if (base.DataGrid != null)
                {
                    base.DataGrid.Refresh(false, true, true, true, true);
                }
            }
        }

        public override bool IsEditable
        {
            get
            {
                return (base.Binding != null);
            }
        }

        public DateTime MaxDate
        {
            get
            {
                return (DateTime)base.GetValue(MaxDateProperty);
            }
            set
            {
                base.SetValue(MaxDateProperty, value);
            }
        }

        public DateTime MinDate
        {
            get
            {
                return (DateTime)base.GetValue(MinDateProperty);
            }
            set
            {
                base.SetValue(MinDateProperty, value);
            }
        }

        public TimeEditorFormat TimeFormat
        {
            get
            {
                return (TimeEditorFormat)base.GetValue(TimeFormatProperty);
            }
            set
            {
                base.SetValue(TimeFormatProperty, value);
            }
        }
    }
}
